昨天把 PRD 該有的東西都湊齊了:摘要、角色、流程、資料、例外、工時。聊到最後使用者通常只想做一件事:把它下載成一份 Word 拿去開會。聽起來是最簡單的收尾,實際做起來卡了不少時間。
問題出在那張流程圖。
前面整套設計,流程圖都是用 Mermaid 寫的純文字。在對話畫面裡,GPTs 有原生的 Mermaid 顯示器,那段程式碼會即時渲染成漂亮的方塊跟箭頭,使用者看得很開心。可是一旦生成 Word,Word 不認得 Mermaid。它只會把那段 flowchart TD 原樣當成文字塞進去,使用者打開檔案,看到的是這樣一段內容:
flowchart TD
A["UI-01 登入頁"] --> B{是否符合資格}
B -->|符合| C["UI-02 服務列表頁"]
B -->|不符合| D["UI-03 資格不符提示"]
當初會用 Mermaid,是看上它是純文字:後續這份文件要交給 AI 接手開發時,機器解析比圖片容易得多。但這個優勢只在機器那一端成立。整份文件最關鍵的一段,在 Word 裡變成一段沒有人會逐行去讀的原始碼。

我一開始想得很單純:那就別等到 Word,從頭到尾都用圖不就好了?使用者每改一次流程,我就在背後把 Mermaid 轉成 JPG 顯示。
GPT 要轉圖只能靠 Code Interpreter,那是一個沙箱裡的 Python 環境。實際呼叫才發現它沒有 mermaid-cli、沒有 Node、也沒有對外網路可以連 mermaid.live。Mermaid 的官方渲染本來就是跑在瀏覽器或 Node 上的,純 Python 沙箱裡沒有現成的渲染器,第一次跑就直接報錯。
退一步說,就算轉得出來,每改一版流程就轉一次圖,每次轉檔好幾秒,對話節奏會被拖垮。使用者還在跟我來回調流程的箭頭,畫面卻一直在轉圈圈,這體驗很糟。
所以這條路兩邊都不通:技術上沙箱轉不動,體驗上也不該轉。
坑踩到這裡,設計反而清楚了。把「看」跟「交付」拆成兩件事。
做法:直接吐 mermaid 程式碼區塊,靠 GPTs 原生顯示器即時渲染。
不轉圖。使用者調流程調得多勤都無所謂,渲染是顯示器即時做的,零成本。這個階段的目標是「快速看、快速改」,圖糊一點、醜一點都沒關係,能即時反映改動最重要。
做法:使用者明確說「產生 Word」,才動用 Code Interpreter 把 Mermaid 轉成 JPG,再用 python-docx 把圖嵌進文件。
整個轉檔的重活,延到最後一刻、而且只做一次。這也是為什麼鼠勾以的交付是兩段式的:先給你可以直接複製的 Markdown 全文,Word 檔當成可選的打包,你要才生成。沒人要 Word 的話,根本不用碰 Code Interpreter。
把這兩段攤開來看,分界很乾淨:對話階段優先「即時」,犧牲畫質;交付階段優先「能看」,才付轉檔的代價。同一張流程圖,在兩個階段用兩種方式呈現。
上面這套用了一陣子,還是不夠。
需求方PM 要這份文件通常有兩個時機。一個是要帶去跟 SA、IT 開會,那份得排版、能印、圖要看得到。另一個是自己收工存檔,或是貼到內部知識庫、丟給下一棒的工具接手,那種要的是乾淨的純文字。我早期一律給 Word,第二種人拿到手還得自己反白複製、再把格式清一遍。
所以在產下載檔之前,多問一句:
這份要拿去跟 IT/SA 討論,還是先定稿?
選「討論」才生成 Word。選「定稿」就直接把對話裡那份 Markdown 全文當正本,不碰 Code Interpreter。
這裡踩到一個當下沒料到的問題。我測「我要 Markdown」的時候,它確實給了我一個檔案,副檔名也是 .md,但打開一看,內容是走完 Word 轉檔流程、結構已經被重排過的版本。它把「給我 Markdown」理解成「把 Word 那條路走完,最後換個副檔名」。另一次我說「定稿了」,它回我一個改了檔名的 Word。
現在寫死了:Markdown 正本就是對話裡組好的那段純文字,不生成檔案、不呼叫 Code Interpreter、不經過 Word。使用者說要 Markdown 或純文字,一律指回對話內全文。
真的要生 Word 的時候,流程大概是這樣串起來:
from docx import Document
from docx.shared import Cm
doc = Document()
# ...前面各章節照模板填...
# 3.0 端對端流程圖:把轉好的 JPG 嵌進來
doc.add_heading('3.0 端對端流程圖', level=2)
doc.add_picture('flowchart.jpg', width=Cm(15))
ps:這段 code 其實是 GPT 自己生的,我沒手刻。我做的只有把需求講清楚(圖嵌在 3.0、寬度 15 公分、轉失敗要有 fallback),剩下交給它寫。這剛好就是整個工具想傳達的事:人把需求說明白,產出讓工具去生。
寬度我固定抓 15 公分,剛好是 A4 直式扣掉邊界後一張圖塞得下、又不會小到看不清節點文字的尺寸。這個數字也是試出來的,太寬會擠破版面,太窄則 UI 編號全糊在一起。
轉圖的時候有一個必須固定的設定:強制 curve: linear。Mermaid 預設把箭頭畫成曲線,簡單的圖還好,節點一多就會互相交疊、看不出哪條連到哪裡。在 init 裡指定直線連接,圖才讀得出來。這條設定從預覽到轉檔都沿用,避免兩邊呈現不一致。
轉出來的圖不一定漂亮。Mermaid 的自動排版碰到節點多、標籤長的流程,偶爾會把兩個框疊在一起,或是讓箭頭直接穿過文字。轉成 JPG 之後那個跑版就定格了,使用者在 Word 裡也拉不動。
所以每張嵌進 Word 的流程圖跟協作圖,正下方固定加一行:
⚠️ 此圖為程式自動轉檔,可能跑版;原始碼見附錄,亦可貼到 mermaid.live 檢視。
這行只加在 Word。對話裡的 mermaid 是顯示器即時渲染的,不會有這個問題,多這行只是噪音。這種只在單一載體成立的規則,我後來都寫在 Word 生成那一段,不寫進 PRD 模板本身,免得對話端也跟著長出一句沒必要的警語。
沙箱環境不穩,轉圖這種事本來就有機率失敗。可能是某個節點文字裡有奇怪字元、可能是沙箱當下記憶體不夠、可能是套件版本對不上。重點是:它一定有失敗的時候,那一刻你不能讓使用者拿到一份開天窗的文件。
我最早的版本就犯了這個錯。轉圖失敗時,那個位置留了一個空白佔位符,使用者下載開來,流程那頁是空的。他不知道是壞了還是我忘了寫,只覺得這工具不靠譜。那次回饋讓我加了一條死規矩:不准留空白。
現在的 fallback 是這樣接的。圖轉失敗,就不硬塞圖了,正文改成嵌入那張流程圖的 Mermaid 原始碼區塊,外加一句白紙黑字的說明:
流程圖自動轉圖失敗,以下為原始碼,可貼到 mermaid.live 產圖;附錄亦保留同份原始碼。
這樣使用者手上至少有內容,知道發生了什麼事,也知道怎麼補救(複製貼到 mermaid.live 兩秒就有圖)。退化成純文字的版面不好看,但比留一頁空白有用。設計一個會失敗的功能時,失敗時的呈現要跟正常時一起想好。
這也對應前面整套設計的一貫做法:狀態不理想的時候照實顯示,不用完整的外觀蓋過去。待確認清單是這樣、工時的低信心度標記是這樣,轉圖 fallback 也是這樣。
Word 生成上線之後我自己下載來看,覺得少了目錄。十幾頁的文件,SA 要找畫面清單得自己捲半天。python-docx 插目錄不難,塞一個 TOC 網域代碼進去,章節都套好 Heading 樣式就行:
TOC \o "1-3" \h \z \u
實際產出來有兩個問題。Word 的網域不會自己算頁碼,使用者得先按 F9 更新才看得到頁數,不然目錄那幾行後面全是空的;而且目錄那頁後面常常多出一整頁空白。我試著在產出後附一句「頁碼請按 F9 更新」,撐了兩天,還是把整個目錄砍了。現在標題頁後面直接接需求完整度總覽,再進正文。
回頭看,那句「請按 F9」本身就是警訊。一個功能要靠一句操作說明才成立,對使用者來說它就是沒做完。
最後這件事,我覺得比前面所有技術細節都值得寫。
有天我下載一份剛產出的 Word,是一個線上請假需求的草稿,翻到流程那頁,又是那段 flowchart TD 語法。整份文件從頭到尾沒有一張圖。我把 .docx 解壓開來確認,裡面根本沒有 media 資料夾,代表它連轉圖那一步都沒跑,直接把語法貼進去交差。
第一反應是規則講得不夠重。我把那段改成硬的:每張圖「必須」先轉成圖片、正文「一律」放圖、「絕不」放原始碼,只有轉圖真的失敗才准放語法,還得標上警告。
隔天再看那份規則,我開始覺得不對勁,這條好像早就寫過了。翻 CHANGELOG 一查,「Word 一律轉圖」很早就定了,中間還對齊過一次,我前一天做的「強化」是同一條規則第三次重講。
真正的問題不在措辭。同一份需求,前一版產出的圖是好的,後一版就沒轉,這是模型執行上的浮動,寫幾個「必須」壓不住。而且整段塞滿「絕不」「唯一例外」讀起來像在跟它吵架,實測下來它在其他地方反而變得綁手綁腳。
所以我把硬措辭退回原本那版:Word 要轉圖嵌正文,轉不出來就走 fallback。偶爾漏轉,有 fallback 接著,這個程度可以接受。同時把散在三個檔案裡的同一條規則收回一處,其他地方只留一個指標。那次之後我給自己加了一條檢查:要加新規則之前,先確認這件事是不是已經寫在別的地方了。Day 7 講 Instructions 瘦身時提過同一件事,只是那時候我還沒把它變成固定動作。
最後所有東西都收進同一份 .docx:流程圖、畫面清單、Feature 規格、待確認清單、工時初估、Mermaid 原始語法、修改歷程,一份打包帶走,不分散成好幾個檔。SA 收到的是一份就好。
寫到這裡,鼠勾以從開場第一句問候、到吐出最後一份 Word,整條路都走完了。
明天是最後一篇,回頭聊聊那些沒寫進正文的東西:Prompt 怎麼防被亂玩、Backlog 的八種觸發怎麼治理這個一直在長的專案。還有一個到現在都還沒解掉的坑:它對「從零釐清新需求」很拿手,可是碰到「改既有功能、手上只有一份口傳沒文件的舊規格」就會水土不服。
這是 iThome 鐵人賽系列文章。明天見。